<template>
  <view v-html="currentHTML"></view>
</template>

<script setup lang="ts">
import {onMounted, ref} from "vue";
import type {Plan, PlayPeriod, Task, WebSocketResponse} from "../../types";
import moment from "moment";

const timers = {
  taskTimer: 0,
};

const currentHTML = ref("");
const currentPlayPeriod = ref<PlayPeriod>();

/** 调度一个任务 */
const runTask = (task: Task, cb: () => void) => {
  return new Promise((resolve) => {
    cb();
    setTimeout(() => {
      resolve(true);
    }, task.duration * 1000);
  });
};

/** 调度图片列表 */
const scheduleTaskList = async (tasks: Task[]) => {
  for (const task of tasks) {
    await runTask(task, () => {
      console.log(`task 执行, 时长${task.duration}s`, task);
      currentHTML.value = task.html;
    });
  }
};

const isTimeBetween = (base: string, from: string, to: string) => {
  return moment(base).isBetween(from, to);
};

const isDateBetween = (base: string, from: string, to: string) => {
  const dividedBase = base.split(":");
  const dividedFrom = from.split(":");
  const dividedTo = to.split(":");

  for (let i = 0; i < 3; i++) {
    const baseTick = Number(dividedBase[i]);
    const fromTick = Number(dividedFrom[i]);
    const toTick = Number(dividedTo[i]);
    // 不在范围内
    if (baseTick < fromTick || baseTick > toTick) {
      return false;
    }

    // 在范围内
    if (baseTick > fromTick && baseTick < toTick) {
      return true;
    }

    // 完全相等的情况，会走到下一个循环判断
  }
  return false;
};

/**
 * 给定多个计划，返回当前时间所处的时间段。
 *
 * 特别地：
 * - 如果没有任何匹配，返回 null
 *
 * @param {PlayPeriod[]} planList 时间段列表
 * @author YuZhanglong <loveyzl1123@gmail.com>
 */
const checkAndGetCurrentPlayPeriod = (planList: Plan[]) => {
  const current = moment.now();
  const res: PlayPeriod[] = [];

  for (const plan of planList) {
    const {startDate, endDate} = plan;

    const isCurrentTimeBetweenPlanDateRange = isTimeBetween(
        moment(current).format("YYYY-M-D"),
        startDate,
        endDate
    );

    if (isCurrentTimeBetweenPlanDateRange) {
      const playPeriodList = plan.playPeriods;
      for (const playPeriod of playPeriodList) {
        const {startTime, endTime} = playPeriod;
        // 暂时只考虑每天
        const isCurrentTimeBetweenPlayPeriodTimeRange = isDateBetween(
            moment(current).format("HH:MM:SS"),
            startTime,
            endTime
        );

        if (isCurrentTimeBetweenPlayPeriodTimeRange) {
          res.push(playPeriod);
        }
      } 
    }
  }
  return res;
};

/**
 * 调度多项计划
 * @param {Plan[]} plans 计划列表
 * @author YuZhanglong <loveyzl1123@gmail.com>
 */
const schedulePlans = (plans: Plan[]) => {
  const matchedPeriodList = checkAndGetCurrentPlayPeriod(plans);
  console.log(matchedPeriodList);
  if (matchedPeriodList.length > 0) {
    // 只取第一项调度
    const periodToSchedule = matchedPeriodList[0];
    console.log(periodToSchedule);
    // 如果发现是同一个调度任务，返回
    if (periodToSchedule === currentPlayPeriod.value) {
      console.log("调度任务相同，执行原任务!");
      return;
    }
    currentPlayPeriod.value = periodToSchedule;
    const tasks = periodToSchedule.html;
    // 计算出这段 task 列表的总时间 taskRange (最后加一秒确保稳定性)
    const taskRange =
        tasks.reduce((prev, curr) => {
          return prev + curr.duration;
        }, 0) + 1;
    console.log("taskRange", taskRange, "tasks", tasks);
    // 立刻调度一次
    scheduleTaskList(tasks);
    // 每隔 taskRange, 执行里面的所有任务
    timers.taskTimer = setInterval(() => {
      scheduleTaskList(tasks);
    }, taskRange * 1000);
  }
};

onMounted(() => {
  uni.connectSocket({
    url: "ws://boe.vinf.top:8081"
  })

  uni.onSocketOpen(() => {
    uni.sendSocketMessage({
      data: JSON.stringify({
        type: "hello",
        mac: "FF:FF:FF:FF:FF:FF",
      })
    })

    uni.sendSocketMessage({
      data: JSON.stringify({
        type: "deviceInfo",
      })
    })
  })

  uni.onSocketMessage((res) => {
    const data: WebSocketResponse & {
      plan: Plan[];
    } = JSON.parse(res.data as string);
    if (data.type === "planList") {
      for (const plan of data.plan) {
        for (const playPeriod of plan.playPeriods) {
          // 这里可能会有脏数据J
          playPeriod.html = JSON.parse(
              (playPeriod.html as unknown as any).replace(/\\\\"/g, `'`)
          );
        }
      }
      console.log("获取到 plan", data.plan);

      if (Array.isArray(data.plan)) {
        schedulePlans(data.plan);
      }
    }
  });
});
</script>
